/**
 * FssCommandLineUIDriver.java
 */
package fss;

import java.io.File;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import fss.client.ui.FssCommandLineUI;
import fss.common.LookupServiceRegistry;
import fss.remote.ServiceRegistry;
import fss.remote.util.RemoteFileService;
import fss.transfer.Transfer;
import fss.transfer.TransferId;
import fss.util.FssUtils;
import fss.util.rmi.RmiId;
import fss.util.rmi.RmiUtils;

/**
 * The driver for the Command Line Client/UI.
 * 
 * @author thinh
 *
 */
public class FssCommandLineUIDriver {
    private static final int QUIT = 10;
    /**
     * The UI object.
     */
    private FssCommandLineUI ui = null;
    /**
     * The main menu.
     */
    private static final String[] MENU = new String[] {
        "Download", // 1
        "Query", // 2
        "Upload", // 3
        "View *client* incomplete transfer(s) - Resume", // 4
        "View *service* incomplete transfer(s) - Resume", // 5
        "View Network", // 6
        "Get Next Available Service Registry", // 7
        "Get File Service Status", // 8
        "Get Local File List", // 9
        "Quit" // 10
    };
    /**
     * Constrcutor.
     * @param id the client id.
     * @throws RemoteException
     */
    public FssCommandLineUIDriver(RmiId id) throws RemoteException {
        ui = new FssCommandLineUI(id);
    }
    /**
     * Unbind the remote client and ignore exceptions.
     */
    public void unbind() {
        ui.unbind();
    }
    /**
     * Download.
     * @throws RemoteException
     */
    public void executeDownload() {
        ui.download();
        System.out.println();
    }
    /**
     * Query.
     * @throws RemoteException
     */
    public void executeQueryOption() {
        ui.query();
        System.out.println();
    }
    /**
     * Upload.
     */
    public void executeUpload() {
        ui.upload();
        System.out.println();
    }
    /**
     * View client incomplete transfer(s).
     */
    public List<Transfer> executeViewClientIncompleteTransferList() {
        System.out.println();
        List<Transfer> incomplete = ui.getIncompleteTransferList();
        System.out.println("Client Incomplete Tranfer List (" + incomplete.size() + ")");
        for(int i = 0; i < incomplete.size(); i++) {
            System.out.println("" + (i+1) + ". " + incomplete.get(i));
        }
        return incomplete;
    }
    /**
     * View file service incomplete tranfer(s).
     */
    public List<Transfer> executeViewFileServiceIncompleteTransferList() throws RemoteException {
        List<Transfer> incomplete = new ArrayList<Transfer>();
        System.out.println();
        RmiId serviceId = FssUtils.getRmiId("- File Service Identifier - ");
        RemoteFileService service = (RemoteFileService) RmiUtils.getRemoteObject(serviceId);
        incomplete = service.getIncompleteTransferList();
        System.out.println();
        System.out.println("File Service Incomplete Tranfer List (" + incomplete.size() + ")");
        for(int i = 0; i < incomplete.size(); i++) {
            System.out.println("" + (i+1) + ". " + incomplete.get(i));
        }
        return incomplete;
    }
    /**
     * View entire network.
     * @throws RemoteException 
     */
    public void executeViewEntireNetwork() throws RemoteException {
        System.out.println();
        List<RmiId> network = LookupServiceRegistry.getAvailableRegistryList();
        System.out.println("Available Service Registries (" + network.size() + ")");
        for(int i = 0; i < network.size(); i++) {
            RmiId registryId = network.get(i);
            ServiceRegistry registry = (ServiceRegistry) RmiUtils.getRemoteObject(registryId);
            
            System.out.println("" + (i+1) + ". " + registryId );
            System.out.println("    Connected Service(s)");
            for(RmiId connected : registry.getRegisteredServiceList()) {
                System.out.println("    - " + connected);
            }
        }
        System.out.println();
    }
    /**
     * Get next available service registry identifier.
     */
    public void executeGetNextAvailableServiceRegistryId() {
        System.out.println();
        RmiId id = LookupServiceRegistry.lookup();
        System.out.println("Next available Service Registry: " + id);
        System.out.println();
    }
    /**
     * Get file service status.
     * @throws RemoteException 
     */
    public void executeFileServiceStatus() throws RemoteException {
        System.out.println();
        RmiId id = FssUtils.getRmiId("- File Service Identifier - ");
        RemoteFileService service = (RemoteFileService) RmiUtils.getRemoteObject(id);
        System.out.println();
        System.out.println("File Service Status (" + id + "): Download:" + service.getDownloadCount() + ", Upload: " + service.getUploadCount());
        
        Map<TransferId, Transfer> transfers = service.getStatus();
        int count = 0;
        for(TransferId tid : transfers.keySet()) {
            System.out.println("" + (count+1) + ". " + transfers.get(tid));
        }
        System.out.println();
    }
    /**
     * Get local file list.
     */
    public void executeClientGetFileList() {
        System.out.println();
        List<File> files = ui.getLocalFileList();
        
        System.out.println("Local File(s) on client (" + files.size() + ")");
        for(int i = 0; i < files.size(); i++) {
            System.out.println("" + (i+1) + ". " + files.get(i).getName());
        }
        System.out.println();
    }
    /**
     * 
     * @throws RemoteException
     */
    public void executeViewFileServiceIncomplistTransferList() throws RemoteException {
        System.out.println();
        RmiId id = FssUtils.getRmiId("- File Service Identifier - ");
        RemoteFileService service = (RemoteFileService) RmiUtils.getRemoteObject(id);
        System.out.println();
        List<Transfer> incomplete = service.getIncompleteTransferList();
        System.out.println("Incomplete Tranfer List on " + id + " (" + incomplete.size() + ")");
        for(int i = 0; i < incomplete.size(); i++) {
            System.out.println("" + (i+1) + ". " + incomplete.get(i));
        }
    }
    /**
     * Application entry.
     * @param args not used.
     * @throws RemoteException 
     */
    public static void main(String[] args) {
        Scanner in = new Scanner(System.in);
        String input = null;
        System.out.println("********************************************************************");      
        System.out.println("FSS Command Line UI Driver (dev-only)");
        System.out.println("********************************************************************");
        System.out.println();
        
        // the client
        RmiId id = FssUtils.getRmiId("- File Service Client Identifier -");
        
        FssCommandLineUIDriver driver = null;
        try {
            driver = new FssCommandLineUIDriver(id);
        } catch (RemoteException e1) {
            e1.printStackTrace();
            System.err.println("Cannot execute this driver program. Program will terminate.");
            System.exit(-1);
        }
        
        int choice = -1;
        System.out.println();
        choice = FssUtils.getMenuOption(null, MENU);
        while(choice != QUIT) {
            switch(choice) {
                case 1: // send download request
                    driver.executeDownload();
                    break;
                case 2: // query
                    driver.executeQueryOption();
                    break;
                case 3: // send upload request
                    driver.executeUpload();
                    break;
                case 4: // view client incomplete transfer(s)
                    List<Transfer> clientIncomplete = driver.executeViewClientIncompleteTransferList();
                    
                    if(clientIncomplete.size() > 0) {
                        System.out.print("Resume a download? (y/n) ");
                        input = in.nextLine();
                        if(input.toLowerCase().charAt(0) == 'y') {
                            System.out.print("Select a transfer from above: ");
                            input = in.nextLine();
                            try {
                                int index = Integer.parseInt(input);
                                Transfer t = clientIncomplete.get(index - 1); // the menu is 1-based
                                driver.ui.resume(t);
                            } catch(Exception e) {
                                e.printStackTrace();
                            }
                        } else {
                            System.out.print("Clear incomplete? (y/n) ");
                            input = in.nextLine();
                            if(input.toLowerCase().charAt(0) == 'y') {
                                driver.ui.clearIncompleteTransferList();
                                System.out.println("Incomplete Transfer(s) cleared.");
                            }
                        }
                    }
                    System.out.println();
                    break;
                case 5: // view service incomplete transfer(s)
                    List<Transfer> serviceIncomplete = null;
                    
                    try {
                        serviceIncomplete = driver.executeViewFileServiceIncompleteTransferList();
                        if(serviceIncomplete.size() > 0){
                            System.out.print("Resume transfer? (y/n) ");
                            input = in.nextLine();
                            if(input.toLowerCase().charAt(0) == 'y') {
                                System.out.print("Select a transfer transfer from above: ");
                                input = in.nextLine();
                                int index = Integer.parseInt(input);
                                Transfer t = serviceIncomplete.get(index - 1); // the menu is 1-based
                                
                                // attempt to connect with the service
                                RemoteFileService service = (RemoteFileService) RmiUtils.getRemoteObject(t.getId().getDestinationId());
                                service.register(driver.ui.getFileServiceClient());
                                service.resume(t.getId());
                            }
                        }
                    } catch (RemoteException e1) {
                        e1.printStackTrace();
                    }
                    System.out.println();
                    break;
                case 6: // view network
                    try {
                        driver.executeViewEntireNetwork();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                case 7: // get next available service registry 
                    driver.executeGetNextAvailableServiceRegistryId();
                    break;
                case 8: // get service registry status
                    try {
                        driver.executeFileServiceStatus();
                    } catch (RemoteException e) {
                        e.printStackTrace();
                    }
                    break;
                case 9: // get local file list
                    driver.executeClientGetFileList();
                    break;
            }
            choice = FssUtils.getMenuOption(null, MENU);
        } 
        
        driver.unbind();
        System.out.println("Testdriver ended.");
        System.exit(0);
    }

}
